package com.bby.screentool.model;

import android.content.Context;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.bby.screentool.base.RuntimeEnv;
import com.bby.screentool.event.Action;
import com.bby.screentool.event.ActionEvent;
import com.bby.screentool.event.ActionEventHandler;
import com.bby.screentool.event.ActionEventListener;
import com.bby.screentool.event.ScreenModelObserver;
import com.bby.screentool.manager.WebRtcResourceManager;
import com.bby.screentool.manager.WebSocketManager;
import com.bby.screentool.utils.SdpObserverAdapter;
import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.AudioTrack;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.ScreenCapturerAndroid;
import org.webrtc.SessionDescription;
import org.webrtc.VideoTrack;

import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;

public class ScreenModel implements WebRtcResourceManager.WebRtcObserver, ActionEventListener {
    private final String TAG = getClass().getName();
    private final WebRtcResourceManager resourceManager = WebRtcResourceManager.getInstance();
    private final WebSocketManager socketManager = WebSocketManager.getInstance();
    private final ActionEventHandler eventHandler = ActionEventHandler.build(this);
    private final ScreenModelObserver screenModelObserver;
    private PeerConnection peerConnection;
    private String targetId = "";

    public ScreenModel(Context context, @NonNull ScreenModelObserver observer) {
        screenModelObserver = observer;
        initEvent(context);
    }

    public void sendOffer(String targetId) {
        if (!checkRecord()) {
            // TODO 询问是否；录屏
            screenModelObserver.onMessageShow("未开启录屏！");
            return;
        }
        VideoTrack videoTrack = resourceManager.getVideoTrack();
        AudioTrack audioTrack = resourceManager.getAudioTrack();
        if (videoTrack == null && audioTrack == null) {
            screenModelObserver.onMessageShow("资源创建失败！");
            return;
        }
        this.targetId=targetId;
        peerConnection.addTrack(videoTrack);
        peerConnection.addTrack(audioTrack);
        peerConnection.createOffer(new SdpObserverAdapter(screenModelObserver, (observer, sdp) -> {
            Log.i(TAG, "sdk 创建成功:" + sdp);
            peerConnection.setLocalDescription(observer, sdp);
            socketManager.send(new Action(Action.OFFER, targetId, sdp.description));
        }), new MediaConstraints());
    }

    @ActionEvent(Action.SCREEN_ID)
    public void onScreenId(Action action) {
        Log.i(TAG, "获取到屏幕id：" + action.getData());
        RuntimeEnv.setScreenId(action.getData());
    }

    // 发送方
    @ActionEvent(Action.ASK)
    public void onAskReceived(Action action) {
        targetId = action.getFrom();
        screenModelObserver.onAsk(action);
    }

    // 接收方
    @ActionEvent(Action.OFFER)
    public void onOfferReceived(Action action) {
        peerConnection.setRemoteDescription(new SdpObserverAdapter(screenModelObserver, ((observer, description) -> {
            Log.i(TAG, "设置远程sdp成功");
        })), new SessionDescription(SessionDescription.Type.OFFER, action.getData()));
        peerConnection.createAnswer(new SdpObserverAdapter(screenModelObserver, ((observer, sdp) -> {
            Log.i(TAG, "answer 创建成功:" + sdp);
            peerConnection.setLocalDescription(observer, sdp);
            socketManager.send(new Action(Action.ANSWER, action.getFrom(), sdp.description));
        })), new MediaConstraints());
    }

    // 发送方
    @ActionEvent(Action.ANSWER)
    public void onAnswerReceived(Action action) {
        peerConnection.setRemoteDescription(new SdpObserverAdapter(screenModelObserver, ((observer, description) -> {
            Log.i(TAG, "设置远程sdp成功");
        })), new SessionDescription(SessionDescription.Type.ANSWER, action.getData()));
    }

    // 两方都有，接收 ICE
    @ActionEvent(Action.ICE)
    public void onIceCandidateReceived(Action action) {
        Log.e(TAG, "接收到 ICE Candidate");
        try {
            JSONObject data = new JSONObject(action.getData());
            peerConnection.addIceCandidate(new IceCandidate(
                    data.getString("id"),
                    data.getInt("label"),
                    data.getString("candidate")
            ));
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    // 两方都有，发送 ICE
    @Override
    public void onIceCandidate(IceCandidate iceCandidate) {
        try {
            JSONObject object = new JSONObject();
            object.put("type", "candidate");
            object.put("label", iceCandidate.sdpMLineIndex);
            object.put("id", iceCandidate.sdpMid);
            object.put("candidate", iceCandidate.sdp);
            socketManager.send(new Action(Action.ICE, targetId, object.toString()));
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    // 接收到数据流
    @Override
    public void onAddStream(MediaStream mediaStream) {
        if (!mediaStream.audioTracks.isEmpty()) {
            Log.i(TAG, "onAddStream: 收到音频流");
            mediaStream.audioTracks.forEach(audioTrack -> audioTrack.setEnabled(true));
//                peerConnection.setAudioPlayout(true);
        }
        screenModelObserver.onAddStream(mediaStream);
    }

    @Override
    public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
        screenModelObserver.onIceConnectionChange(iceConnectionState);
    }

    public void readyRecord(Context context, ScreenCapturerAndroid screenCapturerAndroid) {
        try {
            resourceManager.createResources(context, screenCapturerAndroid);
            peerConnection = WebRtcResourceManager.getInstance().createPeerConnection();
        } catch (Exception e) {
            Log.e(TAG, "初始化 peerConnection 时发生错误", e);
        }
    }

    public void releaseRecording(Context context) {
        resourceManager.releaseResource();
        peerConnection = null;
    }

    public void initEvent(Context context) {
        resourceManager.init(context, this);
        WebSocketManager.getInstance().addListener(new WebSocketListener() {
            @Override
            public void onMessage(@NonNull WebSocket webSocket, @NonNull String message) {
                Action action = new Gson().fromJson(message, Action.class);
                if (action == null) {
                    Log.e("WS:", "错误事件:" + message);
                    return;
                }
                try {
                    eventHandler.invoke(action);
                } catch (Exception e) {
                    Log.e(TAG, "事件分发失败", e);
                }
            }

            @Override
            public void onFailure(@NonNull WebSocket webSocket, @NonNull Throwable t, @Nullable Response response) {

            }
        });
    }

    public boolean startAudioRecord() {
        if (resourceManager.getAudioTrack() == null) {
            return false;
        } else {
            resourceManager.getAudioTrack().setEnabled(true);
        }
        return true;
    }

    public boolean stopAudioRecord() {
        if (resourceManager.getAudioTrack() == null) {
            return false;
        } else {
            resourceManager.getAudioTrack().setEnabled(false);
        }
        return true;
    }

    public boolean checkRecord() {
        return peerConnection != null;
    }
}
